package components;

import java.util.ArrayList;
import java.util.List;

import managers.ComponentManager;
import managers.FeatureManager;
import managers.SemanticsManager;

import org.jdom2.Element;


import features.Feature;
import features.FeatureList;
import ruletree.rule.Word;
public abstract class Component {
	
	public static final String ATTRIBUTE_VAR = "var";
	public static final String ATTRIBUTE_NAME = "name";
	public static final String ROOT = "translation";
	protected ComponentInfo info;
	protected String name;
	protected FeatureList featureList;
	protected String var;
	protected Word word;
	
	protected boolean autoAddDefaultFeaturesInCreation;
	
	//Constructor
	
	protected Component(Element componentElement, Boolean autoAddDefaultFeatures){
		
		this.name = componentElement.getAttributeValue(ATTRIBUTE_NAME);
	
		if(autoAddDefaultFeatures)
			this.featureList = new FeatureList(FeatureManager.getDefaultFeatures(name));
		else
			this.featureList = new FeatureList(new ArrayList<Feature>());
		
		this.word = new Word(componentElement.getAttributeValue(ROOT));
		info = ComponentManager.getInstance().getComponentInfo(name);

		String tagString = componentElement.getAttributeValue(ATTRIBUTE_VAR);
		if(tagString == null)
			var = ATTRIBUTE_VAR;
		else
			var = tagString;
		
		//override defaults
		ArrayList<Feature> specifiedFeatures = SemanticsManager.getSpecifiedFeatures(componentElement);
		for(Feature feature: specifiedFeatures)
			//setFeature(feature);
			addFeature(feature); //used add to accomodate creation of components in rules
		
	}
	
	protected Component(String componentName, boolean autoAddDefaultFeatures){
		this.name = componentName;
		this.autoAddDefaultFeaturesInCreation = autoAddDefaultFeatures;
		info = ComponentManager.getInstance().getComponentInfo(name);
		
		if(autoAddDefaultFeatures)
			this.featureList = new FeatureList(FeatureManager.getDefaultFeatures(componentName));
		else
			this.featureList = new FeatureList(new ArrayList<Feature>());
	
		var = ATTRIBUTE_VAR;
	}
	
	public static Component createInstance(String componentName, boolean autoAddDefaultFeatures){
		Component newComponent;
		
		if(ComponentManager.getInstance().isLeaf(componentName))
			newComponent = new Leaf(componentName, autoAddDefaultFeatures);
		else
			newComponent = new Phrase(componentName, autoAddDefaultFeatures);
		
		return newComponent;
	}
	
	public static Component createInstance(Element e, boolean autoAddDefaultFeatures){
		String componentName = e.getAttributeValue(ATTRIBUTE_NAME);
		
		if(ComponentManager.getInstance().isLeaf(componentName)){
			return new Leaf(e, false);
		}
		else{
			List<Element> childrenElements = (List<Element>)e.getChildren(SemanticsManager.COMPONENT);
			if(childrenElements == null)
				childrenElements = new ArrayList<Element>();

			Phrase phrase = new Phrase(e, false);
			for(Element child: childrenElements)
				phrase.addChild(createInstance(child, false));
			
			return phrase;
		}
	}
	
	
		
	//Abstract Methods
	protected abstract String getFeatures(boolean includeDefaults, String nextLineToken);
	
	protected abstract void addAdditionalXMLContent(Element parentElement);
	
	public abstract String toString();

	public abstract String toGeneratedString();
	
	public abstract String toRawSentence();
	
	public abstract String toSentence();
	
	public abstract boolean isLeaf();
	
	public abstract Children getChildren();
	
	//Getters

	public String getDescription(){
		if(info != null)
			return info.getDescription();
		return name;
	}
	
	public String getName(){
		return name;
	}
	
	public String getVar() {
		return var;
	}

	public Word getWord() {
		return word;
	}
	

	public String getFeaturesInHTML(boolean includeDefaults){
		return getFeatures(includeDefaults, "<br>");
	}
	
	public String getFeaturesInString(boolean includeDefaults) {
		return getFeatures(includeDefaults, "\n");
	}
	
	public Feature getFeature(String featureName){
		if(featureList == null)
			return null;
		
		return featureList.getFeature(featureName);
	}

	public ArrayList<Feature> getFeatureList(){
		return featureList.getFeatureList();
	}
	//Setters
	public void setFeature(Feature newFeature){
		featureList.setFeature(newFeature);
	}
	public void setFeatureList(FeatureList featureList){
		this.featureList = featureList;
	}
	public void setVar(String var){
		this.var = var;
	}
	
	public void setWord(Word word){
		this.word = word;
	}
	
	public void addFeature(Feature newFeature){
		featureList.addFeature(newFeature);
	}
	//Methods related to generating XML file
	public Element generateXMLElement(){
		Element xmlElement = new Element("component");
		xmlElement.setAttribute(ATTRIBUTE_NAME, name);
		
		if(this.var != null){
			xmlElement.setAttribute(ATTRIBUTE_VAR, this.var);
		}
		
		if(this.word != null){
			xmlElement.setAttribute(ROOT, this.word.getRoot());
		}
	
		if(this.featureList != null){
			Element featuresElement = featureList.generateXMLElementForComponent(name);
			if(featuresElement != null)
				xmlElement.addContent(featuresElement);
		}
		addAdditionalXMLContent(xmlElement);
		return xmlElement;
	}
	
	public Component findComponent(Component node, String var){
		return null;
	}
		
}